/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.company.regis.controller;

import com.company.regis.bean.UserCriteria;
import com.company.regis.db.entity.Amphur;
import com.company.regis.db.entity.District;
import com.company.regis.db.entity.Province;
import com.company.regis.db.entity.RegAddress;
import com.company.regis.db.entity.RegUser;
import com.company.regis.db.entity.ReportUser;
import com.company.regis.db.entity.ViewUserDetail;
import com.company.regis.services.DropDownServices;
import com.company.regis.services.GennericService;
import com.company.regis.services.ReportServices;
import com.company.regis.services.UserServices;
import com.company.regis.services.impl.LazyViewUserImpl;
import com.company.regis.utils.JsfUtil;
import java.awt.event.ActionEvent;
import java.io.File;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.annotation.PostConstruct;
import javax.faces.FacesException;
import javax.faces.application.FacesMessage;
import javax.faces.bean.ManagedBean;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.ViewScoped;
import javax.faces.context.ExternalContext;
import javax.faces.context.FacesContext;
import javax.imageio.stream.FileImageOutputStream;
import javax.servlet.ServletContext;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import net.sf.jxls.transformer.XLSTransformer;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.primefaces.event.CaptureEvent;
import org.primefaces.model.LazyDataModel;
import org.primefaces.model.chart.BarChartSeries;
import org.primefaces.model.chart.CartesianChartModel;
import org.primefaces.model.chart.ChartSeries;
import org.primefaces.model.map.LatLng;
import org.primefaces.model.map.MapModel;
import org.primefaces.model.map.Marker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 *
 * @author totoland
 */
@ManagedBean
@ViewScoped
public class UserController extends BaseController {

    private static final long serialVersionUID = -5012598286153889471L;
    private static Logger logger = LoggerFactory.getLogger(UserController.class);

    private RegUser regUser = new RegUser();
    private RegAddress regAddress = new RegAddress();
    private String validatePassword;

    @ManagedProperty(value = "#{gennericService}")
    private GennericService<RegUser> gennericService;
    @ManagedProperty(value = "#{dropDownServices}")
    private DropDownServices dropDownServices;
    @ManagedProperty(value = "#{userServices}")
    private UserServices userServices;
    @ManagedProperty(value = "#{reportServices}")
    private ReportServices reportServices;

    private UserCriteria userCriteria = new UserCriteria();

    private List<Province> listProvinces;
    private List<Amphur> listAmphurs;
    private List<District> listDistricts;
    private List<ViewUserDetail> viewUserDetails;

    private String userPhoto;

    private LazyDataModel<ViewUserDetail> userDetailsLazy;

    @PostConstruct
    public void init() {
        logger.trace("init user management!!");

        initDropDown();
        loadLazy();
    }

    public void initDropDown() {
        listProvinces = dropDownServices.getAllProvince();
    }

    public List<Amphur> getListAmpur(String provinceId) {
        listAmphurs = dropDownServices.getAmphurByProvinceId(provinceId);
        return listAmphurs;
    }

    public List<District> getListDistric(String amphurId) {
        listDistricts = dropDownServices.getDistrictByAmphurId(amphurId);
        return listDistricts;
    }

    public void search() {

        logger.trace("userCriteria : {}", userCriteria);

        viewUserDetails = userServices.findByCriteria(userCriteria);

    }

    public void reset() {

        logger.trace("Reset");

        viewUserDetails = new ArrayList<ViewUserDetail>();
        userCriteria = new UserCriteria();

    }

    public void save() {

        logger.trace("Before Save : {}", regUser);

        regUser.setRegAddress(regAddress);
        regAddress.setRegUser(regUser);

        if (!validateForm()) {
            return;
        }

        logger.trace("Before Save Process.....");

        try {

            gennericService.create(regUser);

            JsfUtil.addSuccessMessage("Saved data Success!!");

            loadLazy();

            JsfUtil.closeDialog("dlgCreateUser");

        } catch (Exception ex) {

            JsfUtil.addErrorMessage("Saved data Fail!!");

            logger.error("Save fail", ex);
        }
    }

    public void loadUser() {

        logger.trace("Load User!!");

        viewUserDetails = userServices.getAllUserDetail();

    }

    public void loadLazy() {

        logger.trace("loadLazy User!!");

        viewUserDetails = userServices.getAllUserDetail();

        final Integer count = userServices.countByCriteria(userCriteria);

        if (count != null && count > 0) {

            LazyViewUserImpl reportModel = new LazyViewUserImpl();
            reportModel.setRowCount(count);
            reportModel.setUserCriteria(userCriteria);
            reportModel.setUserServices(userServices);

            userDetailsLazy = reportModel;

        }

    }

    public void initCreatePopup() {

        logger.trace("initCreatePopup");

        regUser = new RegUser();
        regAddress = new RegAddress();
        regAddress.setRegUser(regUser);
        regUser.setRegAddress(regAddress);

    }

    public void initEditPopup(Integer selectedRow) {

        logger.trace("Selected row : {}", selectedRow);

        regUser = userServices.findById(selectedRow);

        logger.trace("regUser : {}", regUser);

        regAddress = regUser.getRegAddress();
        validatePassword = regUser.getUserPassword();

        JsfUtil.openDialog("dlgUser");

    }

    public void edit() {

        logger.trace("Before Save : {}", regUser);

        regUser.setRegAddress(regAddress);
        regAddress.setRegUser(regUser);

        if (!validateForm()) {
            return;
        }

        logger.trace("Before Edit Process.....");

        try {

            gennericService.edit(regUser);

            JsfUtil.addSuccessMessage("Edit data Success!!");

            loadLazy();

        } catch (Exception ex) {

            JsfUtil.addErrorMessage("Edit data Fail!!");

            logger.error("Edit fail", ex);
        }

    }

    public void delete(Long selectedRow) {

        logger.trace("Before delete Id : {}", selectedRow);

        try {

            RegUser deleteUser = gennericService.find(selectedRow, RegUser.class);

            gennericService.remove(deleteUser);

            JsfUtil.addSuccessMessage("Delete data Success!!");

            loadLazy();

        } catch (Exception ex) {

            JsfUtil.addErrorMessage("Edit data Fail!!");

            logger.error("Edit fail", ex);
        }

    }

    public void fileExportXLS() {

        String reportName = "userReport.xls";

        HSSFWorkbook wb = null;
        InputStream is = FacesContext.getCurrentInstance().getExternalContext().getResourceAsStream("/template/" + reportName);
        XLSTransformer transformer = new XLSTransformer();

        try {

            List<ViewUserDetail> allUsers = userServices.getAllUserDetail();

            Map<String, Object> beans = new HashMap<String, Object>();
            beans.put("header", "Header Report User");
            beans.put("datetime", new Date());
            beans.put("list", allUsers);

            wb = transformer.transformXLS(is, beans);

            FacesContext ctx = FacesContext.getCurrentInstance();
            ExternalContext ectx = ctx.getExternalContext();

            HttpServletResponse response = (HttpServletResponse) ectx.getResponse();
            response.setContentType("application/vnd.ms-excel");
            response.setHeader("Content-Disposition", "attachment; filename=\"" + new Date().getTime() + ".xls\"");

            ServletOutputStream out = response.getOutputStream();
            wb.write(out);
            out.flush();
            out.close();

            ctx.responseComplete();
        } catch (Exception ex) {
            logger.error("cannot export report", ex);
            JsfUtil.alertJavaScript(ex.getMessage());

        } finally {

        }
    }

    private CartesianChartModel groupProvince;

    public void gennerateReportGroupByProvince() {

        groupProvince = new CartesianChartModel();

        List<ReportUser> reportUsers = reportServices.groupByProvince();

        ChartSeries prov = new ChartSeries();
        prov.setLabel("Province N");

        for (ReportUser reportUser : reportUsers) {

            prov.set(reportUser.getProvinceName(), reportUser.getCounts());

        }
        getGroupProvince().addSeries(prov);
        
        ChartSeries prov2 = new ChartSeries();
        
        prov2.setLabel("Province S");

        for (ReportUser reportUser : reportUsers) {

            prov2.set(reportUser.getProvinceName(), reportUser.getCounts());

        }

        getGroupProvince().addSeries(prov2);

    }

    private boolean validateForm() {

        if (!regUser.getUserPassword().equals(validatePassword)) {

            JsfUtil.addErrorMessage("Invalid Password!!");

            return false;
        }

        return true;

    }

    private String getRandomImageName() {
        int i = (int) (Math.random() * 10000000);

        return String.valueOf(i);
    }

    public void oncapture(CaptureEvent captureEvent) {
        userPhoto = getRandomImageName() + ".png";
        byte[] data = captureEvent.getData();

        ServletContext servletContext = (ServletContext) FacesContext.getCurrentInstance().getExternalContext().getContext();

        File dir = new File(servletContext.getRealPath("") + File.separator + "photocam");

        if (!dir.isDirectory()) {
            dir.mkdirs();
        }

        String newFileName = servletContext.getRealPath("") + File.separator + "photocam" + File.separator + userPhoto;

        FileImageOutputStream imageOutput;
        try {
            imageOutput = new FileImageOutputStream(new File(newFileName));
            imageOutput.write(data, 0, data.length);
            imageOutput.close();
        } catch (Exception e) {
            throw new FacesException("Error in writing captured image.");
        }
    }

    /**
     * @return the regUser
     */
    public RegUser getRegUser() {
        return regUser;
    }

    /**
     * @param regUser the regUser to set
     */
    public void setRegUser(RegUser regUser) {
        this.regUser = regUser;
    }

    /**
     * @return the validatePassword
     */
    public String getValidatePassword() {
        return validatePassword;
    }

    /**
     * @param validatePassword the validatePassword to set
     */
    public void setValidatePassword(String validatePassword) {
        this.validatePassword = validatePassword;
    }

    /**
     * @return the gennericService
     */
    public GennericService<RegUser> getGennericService() {
        return gennericService;
    }

    /**
     * @param gennericService the gennericService to set
     */
    public void setGennericService(GennericService<RegUser> gennericService) {
        this.gennericService = gennericService;
    }

    /**
     * @return the userPhoto
     */
    public String getUserPhoto() {
        return userPhoto;
    }

    /**
     * @param userPhoto the userPhoto to set
     */
    public void setUserPhoto(String userPhoto) {
        this.userPhoto = userPhoto;
    }

    /**
     * @return the regAddress
     */
    public RegAddress getRegAddress() {
        return regAddress;
    }

    /**
     * @param regAddress the regAddress to set
     */
    public void setRegAddress(RegAddress regAddress) {
        this.regAddress = regAddress;
    }

    /**
     * @return the dropDownServices
     */
    public DropDownServices getDropDownServices() {
        return dropDownServices;
    }

    /**
     * @param dropDownServices the dropDownServices to set
     */
    public void setDropDownServices(DropDownServices dropDownServices) {
        this.dropDownServices = dropDownServices;
    }

    /**
     * @return the listProvinces
     */
    public List<Province> getListProvinces() {
        return listProvinces;
    }

    /**
     * @param listProvinces the listProvinces to set
     */
    public void setListProvinces(List<Province> listProvinces) {
        this.listProvinces = listProvinces;
    }

    /**
     * @return the listAmphurs
     */
    public List<Amphur> getListAmphurs() {
        return listAmphurs;
    }

    /**
     * @param listAmphurs the listAmphurs to set
     */
    public void setListAmphurs(List<Amphur> listAmphurs) {
        this.listAmphurs = listAmphurs;
    }

    /**
     * @return the listDistricts
     */
    public List<District> getListDistricts() {
        return listDistricts;
    }

    /**
     * @param listDistricts the listDistricts to set
     */
    public void setListDistricts(List<District> listDistricts) {
        this.listDistricts = listDistricts;
    }

    /**
     * @return the userServices
     */
    public UserServices getUserServices() {
        return userServices;
    }

    /**
     * @param userServices the userServices to set
     */
    public void setUserServices(UserServices userServices) {
        this.userServices = userServices;
    }

    /**
     * @return the viewUserDetails
     */
    public List<ViewUserDetail> getViewUserDetails() {
        return viewUserDetails;
    }

    /**
     * @param viewUserDetails the viewUserDetails to set
     */
    public void setViewUserDetails(List<ViewUserDetail> viewUserDetails) {
        this.viewUserDetails = viewUserDetails;
    }

    /**
     * @return the userCriteria
     */
    public UserCriteria getUserCriteria() {
        return userCriteria;
    }

    /**
     * @param userCriteria the userCriteria to set
     */
    public void setUserCriteria(UserCriteria userCriteria) {
        this.userCriteria = userCriteria;
    }

    /**
     * @return the userDetailsLazy
     */
    public LazyDataModel<ViewUserDetail> getUserDetailsLazy() {
        return userDetailsLazy;
    }

    /**
     * @param userDetailsLazy the userDetailsLazy to set
     */
    public void setUserDetailsLazy(LazyDataModel<ViewUserDetail> userDetailsLazy) {
        this.userDetailsLazy = userDetailsLazy;
    }

    private MapModel emptyModel;

    private String title;

    private double lat;

    private double lng;

    public MapModel getEmptyModel() {
        return emptyModel;
    }

    public void addMessage(FacesMessage message) {
        FacesContext.getCurrentInstance().addMessage(null, message);
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public double getLat() {
        return lat;
    }

    public void setLat(double lat) {
        this.lat = lat;
    }

    public double getLng() {
        return lng;
    }

    public void setLng(double lng) {
        this.lng = lng;
    }

    public void addMarker(ActionEvent actionEvent) {
        Marker marker = new Marker(new LatLng(lat, lng), title);
        emptyModel.addOverlay(marker);

        JsfUtil.addSuccessMessage("Marker Added Lat:" + lat + ", Lng:" + lng);
    }

    /**
     * @return the reportServices
     */
    public ReportServices getReportServices() {
        return reportServices;
    }

    /**
     * @param reportServices the reportServices to set
     */
    public void setReportServices(ReportServices reportServices) {
        this.reportServices = reportServices;
    }

    /**
     * @return the groupProvince
     */
    public CartesianChartModel getGroupProvince() {
        return groupProvince;
    }

    /**
     * @param groupProvince the groupProvince to set
     */
    public void setGroupProvince(CartesianChartModel groupProvince) {
        this.groupProvince = groupProvince;
    }
}
